<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Vue组件Demo</title>
		<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<!-- 引用自定义组件 -->
			<h3>引用自定义组件</h3>
			<button-counter></button-counter>
			<hr >
			<br>
			<!-- 组件复用 -->
			<h3>组件复用</h3>
			<button-counter></button-counter>
			<button-counter></button-counter>
			<hr >
			<br>
			<!-- 通过prop向自定义组件传递数据 -->
			<h3>通过prop向自定义组件传递数据</h3>
			<hello name="John"></hello>
			<hr >
			<br>
			<!-- 通过v-bind传递Vue实例中的动态数据到组件中 -->
			<h3>通过v-bind传递Vue实例中的动态数据到组件中</h3>
			<hello :name="name"></hello>
			<hr >
			<br>
			<!-- 给组件添加事件 -->
			<h3>给组件添加事件</h3>
			<event-demo></event-demo>
			<hr >
			<br>
			<!-- 在父组件中监听子组件事件 -->
			<h3>在父组件中监听子组件事件</h3>
			<event-demo2 @subclick="subClickHandle"></event-demo2>
			<hr >
			<br>
			
			<!-- 通过子组件设置父组件中的文字的大小 -->
			<h3>通过子组件设置父组件中的文字的大小</h3>
			<div>
				<p :style="{fontSize: pFontSize+'em'}">
					我是父组件中的一段文字
				</p>
				<!-- 事件处理函数写法 -->
				<set-fontsize @changefontsize="changeFontSize"></set-fontsize>
				<!-- 内联写法，注意不能写this.pFontSize = $event -->
				<set-fontsize @changefontsize="pFontSize = $event"></set-fontsize>
			</div>
			<hr >
			<br>
			
			<!-- 让自定义组件支持v-model -->
			<h3>让自定义组件支持v-model</h3>
			<my-input v-model="text"></my-input><br>
			当前text数据：{{text}}
			<hr >
			<br>
			
			<!-- 通过slot插入内容 -->
			<h3>通过slot插入内容</h3>
			<my-article>这是文章的主题内容</my-article>
			<hr >
			<br>
				
			<!-- 动态标签 -->
			<h3>动态标签</h3>
			<component :is="tag" v-model="text"></component>
			<hr >
			<br>
			
			<!-- 给组件绑定原生事件 -->
			<h3>通过父组件给子组件绑定原生事件</h3>吗
			<h5>方案一 使用$listeners属性</h5>
			<my-input2 :tag="'用户名'" v-model="text" @focus="subFocusHandle" @blur="subBlurHandle"></my-input2>
			<h5>方案二 使用.native修饰符（只能在子组件根元素上监听事件）</h5>
			<my-input3 @focus.native="subFocusHandle" @blur.native="subBlurHandle" :tag="'通过.native修饰符绑定原生事件'"></my-input3>
			<hr >
			<br>
		</div>
	</body>
	<script type="text/javascript">
		// 组件一 组件简单使用
		Vue.component('buttonCounter', {
			template: '<div><button @click="counter++">点击</button><br/>您点击了{{counter}}次按钮.</div>',
			// 在组件中data必须是一个函数
			data: function(){
				return {
					counter:0
				}
			}
		});
		
		// 组件二  通过props向组件中传递数据（属性的值可以当成data中的数据来引用)
		Vue.component('hello', {
			template: `<div>hello, <b>{{name}}</b>!</div>`,
			props: ['name']
		});
		
		// 组件三  在子组件中监听事件
		Vue.component('eventDemo', {
			template: `
				<div>
					<button @click='clickHandle'>测试按钮</button>
				</div>
			`,
			methods: {
				clickHandle: function(){
					alert('点击了组件中的按钮');
				}
			}
			
		});
		
		// 组件四  在父组件中监听子组件事件
		Vue.component('eventDemo2', {
			template: `
				<div>
					<button @click='$emit("subclick")'>测试按钮</button>
				</div>
			`,
			methods: {
				clickHandle: function(){
					alert('点击了组件中的按钮');
				}
			}
		});
		
		// 组件五  通过子组件设置父组件文字大小（在父组件中监听子组件事件，并在事件中传递参数）
		Vue.component('set-fontsize', {
			template: `
				<div>
					<input type='number' v-model='fontSize' /> em
					<button @click="$emit('changefontsize', fontSize)">确定</button>
				</div>
			`,
			data: function(){
				return {fontSize: 1}
			}
		});
				
		// 组件六 让自定义组件支持v-model
		Vue.component('my-input', {
			template:`<input :value='value' @input='$emit("input", $event.target.value)' />`,
			props: ['value']
		});
		
		// 组件七 通过slot插入内容
		Vue.component('my-article', {
			template:`
				<div>
					<h3>这是一篇文章</h3>
					<p><slot></slot></p>
				</div>
			`
		});
		
		// 组件八 给组件绑定原生事件
		Vue.component('my-input2',{
			template: `
				<label>
					{{tag}}
					<input v-on="myListeners" v-bind="$attrs" />
				</label>
			`,
			props: ['tag'],
			computed: {
			myListeners: function(){
				var _this = this;
				// 1、将父组件中绑定的所有事件（除了.native修饰符修饰的事件）处理函数绑定到子组件中
				// 2、重写子组件input事件处理函数（确保子组件能适配v-model）
				return Object.assign({}, _this.$listeners, {
					input: function(event){
						_this.$emit('input', event.target.value);
					},
				});
			}
			}
		});
		// 组件九 通过.native修饰符绑定原生事件
		Vue.component('my-input3',{
			template: `
				<input v-bind="$attrs" />
			`,
			props: ['tag']
		});

		let app = new Vue({
			el: '#app',
			data: {
				name: 'Jarry',
				pFontSize: 1,
				text: '子组件中的文本',
				tag: 'my-input'
			},
			methods: {
				subClickHandle: function(){
					alert('点击了子组件中的按钮');
				},
				subFocusHandle: function(){
					console.log('子组件得到焦点');
				},
				subBlurHandle: function(){
					console.log('子组件失去焦点');
				},
				// 这里的fontSize参数就是子组件自定义事件传递出来的数据，如果是内联写法可以使用$event引用
				changeFontSize: function(fontSize) {
					console.log('子组件事件中传出来要把字号更改为：' + fontSize);
					this.pFontSize = fontSize;
				}
			}
		});
	</script>
</html>
